home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
libs
/
knowhow4
/
gbuf.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-10
|
24KB
|
696 lines
#include <stdlib.h>
#include "gbuf.h"
#include "move.h"
#include "imagebuf.h"
#include <string.h>
int s_max_color(int bitpx, int nplanes) // Return max color in image
{
int src_max_color;
switch(bitpx)
{
case 8: src_max_color = 255; break;
case 2: src_max_color = 3; break;
case 1:
src_max_color = (nplanes == 1) ? 1 : 15; break;
}
return src_max_color;
}
/////////////////////////////
int get_color_mult(int src_max_color, int dest_max_color) // color scaling
{ // if modes are
if(dest_max_color >= src_max_color) // incompatible
return dest_max_color / src_max_color;
return src_max_color / dest_max_color;
}
///////////////////////////
inline int bw_pix(int color, int x, int y) // Transform color pix
{ // to B/W using pattern
int sx = x % 8; // We suppose that 1st
int sy = y % 8; // 16 patterns approxi-
return (pattern[color][sy]) & (1 << sx) ? 1 : 0; // mates 16 colors
}
////////////////////////
int image_size(int width, int height, int bitpx, int nplanes) // BGI imagesize
{ // works incor-
return ((width * bitpx + 7) >> 3) * nplanes * height; // rect
}
////////////////////////
GrafBuffer::GrafBuffer(loc dim, char* swapName, rect sa, int bpx, int np)
{
loaded = 0; // Buffer is not cleared
buf_dim = dim; // Buffer dimentions, pixels
file_name = strdup(swapName); // Swap file
loc disp(bpx, np); // Display bpx and nplanes
bitpx = disp.X; // Bit per pixel
nplanes = disp.Y; // Number of planes
bound_size.X = buf_dim.X; // Bound is swap area in memory
bound_size.Y = BOUND_SIZE / image_size(dim.X, 1, bitpx, nplanes); // calculation of bound size
FILE* Buf = fopen(file_name, "w+b"); // Buffer file, create it and
fclose(Buf); // immediately close
screen_area = sa; // Screen area (viewport)
screen_position = rect(0, 0, sa.width() - 1, sa.height() - 1);
image = NULL; // Keeps the bound
}
///////////////////////
void GrafBuffer::clear()
{
rewind(buffer);
long len = imagesize();
for(long i = 0; i < len; i++)
fputc(255, buffer);
loaded = 1; // Image allocated on disk
}
///////////////////////
int GrafBuffer::b_open() // Open swap file (created by constructor)
{
if(!(image = (imageP)malloc(BOUND_SIZE + sizeof(imageP))))
return 0;
buffer = fopen(file_name, "r+b");
image->xmax = bound_size.X - 1;
image->ymax = bound_size.Y - 1;
return 1;
}
///////////////////////
void GrafBuffer::b_close() // Close swap file
{
fclose(buffer);
delete image;
image = NULL;
}
///////////////////////
long GrafBuffer::imagesize()
{
long size = image_size(buf_dim.X, 1, bitpx, nplanes) - sizeof(imageP);
size *= buf_dim.Y;
return size;
}
///////////////////////
void GrafBuffer::buffer_disk(rect src, char* name)
{
FILE* work;
work = fopen(name, "w+b");
int end_bound = src.corner.Y / bound_size.Y + 1; // lower bound
int start_bound = src.origin.Y / bound_size.Y; // upper bound
for(int i = start_bound; i < end_bound; i++) // for b. involved
{
get_bound(i); // Read bound from disk
int s_y = (i > start_bound) ? 0 // y coord inside image
: src.origin.Y - i * bound_size.Y;
int e_y = (i < end_bound - 1) ? bound_size.Y - 1
: src.corner.Y - i * bound_size.Y;
int image_x = image->xmax; // We intend to cut
int image_y = image->ymax; // image and need reserv
cut_image(image, rect(0, 0, image->xmax, image->ymax),
rect(src.origin.X, s_y, image->xmax, image->ymax));
cut_image(image, rect(0, 0, image->xmax, image->ymax),
rect(0, 0, src.corner.X - src.origin.X, e_y));
fwrite(image->data, image_size(src.width(), e_y - s_y + 1,
bitpx, nplanes), 1, work);
image->xmax = image_x;
image->ymax = image_y;
}
fclose(work);
}
//////////////////////
void GrafBuffer::get_BW(int number)
{
int plane_size = (bound_size.X + 7) >> 3; // size of plane
int scan_size = plane_size << 2; // size of scan line
imageP work =
(imageP)malloc(scan_size + sizeof(imageP)); // bitpx, nplanes));
work->xmax = bound_size.X - 1; // We construct one-line
work->ymax = 0; // "work" image; "image"
image->ymax = (bound_size.Y - 1) << 2; // was color, "work" - BW
int size = plane_size * bound_size.Y; // size of one (of 4) bounds
int i, j, x; // image(COL)->work(BW)->image(BW)
ImageBuffer im; // Buffer for 8 pixels of byte
int vert_sh = bound_size.Y * number; // Offset in "buffer" file
fseek(buffer, (long)(number) * size * 4, SEEK_SET);
for(i = 0; i < 4; i++) // For 4 planes
{
for(j = 0; j < bound_size.Y; j++) // For all scan lines
{
fread(work->data, scan_size, 1, buffer);
for(x = 0; x < plane_size; x++) // For plane
{
unsigned char pix = im.image_get_pixel(work, x,
vert_sh + j);
image->data[x + i * size + j * plane_size] = pix;
}
}
}
delete work;
}
//////////////////////
imageP GrafBuffer::get_bound(int number) // get number-th bound, from 0
{
int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
fseek(buffer, (long)number * size, SEEK_SET);
fread(image->data, size, 1, buffer);
return image;
}
//////////////////////
void GrafBuffer::put_bound(int number)
{
int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
fseek(buffer, (long)number * size, SEEK_SET);
fwrite(image->data, size, 1, buffer);
}
//////////////////////
void GrafBuffer::bound_screen(int number, loc comp_s, loc comp_d)
{
if(bound_size.Y * (number + 1) < screen_position.origin.Y // If this bound
|| bound_size.Y * number >= screen_position.corner.Y) // is invisible
return;
image = get_bound(number); // Read this bound
int y1 = (screen_position.origin.Y > number * bound_size.Y) // screen
? screen_area.origin.Y
: screen_area.origin.Y
+ (long)(number * bound_size.Y
- screen_position.origin.Y) * comp_d.Y / comp_s.Y;
int y3 = (screen_position.origin.Y > number * bound_size.Y)
? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
int y4 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
? screen_position.corner.Y - number * bound_size.Y // image
: bound_size.Y;
image_screen(image, rect(screen_position.origin.X, y3,
screen_position.corner.X, y4),
loc(screen_area.origin.X, y1),
bitpx, nplanes,
comp_s, comp_d);
}
//////////////////////
void GrafBuffer::screen_bound(int number)
{
if(bound_size.Y * (number + 1) < screen_position.origin.Y
|| bound_size.Y * number > screen_position.corner.Y)
return;
image = get_bound(number);
int y1 = (screen_position.origin.Y > number * bound_size.Y)
? screen_area.origin.Y
: screen_area.origin.Y + number * bound_size.Y
- screen_position.origin.Y;
int y2 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
? screen_area.corner.Y - 1
: screen_area.origin.Y + (number + 1) * bound_size.Y
- screen_position.origin.Y - 1;
int y3 = (screen_position.origin.Y > number * bound_size.Y)
? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
screen_image(image, rect(screen_area.origin.X, y1,
screen_area.corner.X, y2),
loc(screen_position.origin.X, y3));
put_bound(number);
}
//////////////////////
void GrafBuffer::buffer_screen(loc comp_s, loc comp_d)
{
int bound_num = buf_dim.Y / bound_size.Y + 1;
for(int i = 0; i < bound_num; i++)
bound_screen(i, comp_s, comp_d);
}
//////////////////////
void GrafBuffer::buffer_screen(rect temp, // temp - on screen
loc comp_s, loc comp_d)
{
int start_bound = ((long)(temp.origin.Y - screen_area.origin.Y)
* comp_s.Y / comp_d.Y + screen_position.origin.Y)
/ bound_size.Y;
int end_bound = ((long)(temp.corner.Y - screen_area.origin.Y)
* comp_s.Y / comp_d.Y + screen_position.origin.Y)
/ bound_size.Y + 1;
for(int i = start_bound; i < end_bound; i++)
{
image = get_bound(i);
int y1 = ((long)(temp.origin.Y
- screen_area.origin.Y) * comp_s.Y / comp_d.Y
+ screen_position.origin.Y
> i * bound_size.Y) // screen
? temp.origin.Y
: screen_area.origin.Y
+ (long)(i * bound_size.Y
- screen_position.origin.Y) * comp_d.Y / comp_s.Y;
int y3 = ((long)(temp.origin.Y - screen_area.origin.Y)
* comp_s.Y / comp_d.Y + screen_position.origin.Y
> i * bound_size.Y)
? screen_position.origin.Y - i * bound_size.Y
+ (long)(temp.origin.Y - screen_area.origin.Y)
* comp_s.Y / comp_d.Y
: 0;
int y4 = (screen_position.origin.Y + (temp.corner.Y
- screen_area.origin.Y) * comp_s.Y / comp_d.Y
< (i + 1) * bound_size.Y)
? screen_position.origin.Y + (long)(temp.corner.Y
- screen_area.origin.Y) * comp_s.Y / comp_d.Y
- i * bound_size.Y // image
: bound_size.Y;
image_screen(image,
rect(screen_position.origin.X + (long)(temp.origin.X
- screen_area.origin.X) * comp_s.X / comp_d.X, y3,
screen_position.origin.X + (long)(temp.corner.X
- screen_area.origin.X) * comp_s.X / comp_d.X, y4),
loc(temp.origin.X, y1),
bitpx, nplanes,
comp_s, comp_d, 1);
}
}
//////////////////////
void GrafBuffer::screen_buffer()
{
int bound_num = buf_dim.Y / bound_size.Y + 1;
for(int i = 0; i < bound_num; i++)
screen_bound(i);
}
//////////////////////
void GrafBuffer::scroll(int shift, int direction, int show)
{
rect reserv = screen_area;
rect res = screen_position;
switch(direction)
{
case UP:
if(screen_position.corner.Y + shift > buf_dim.Y)
return;
screen_position.origin.Y += shift;
screen_position.corner.Y += shift;
if(show)
buffer_screen();
return;
case DN:
if(screen_position.origin.Y - shift < 0)
return;
screen_position.origin.Y -= shift;
screen_position.corner.Y -= shift;
if(show)
buffer_screen();
return;
case LEFT:
if(screen_position.corner.X + shift > buf_dim.X)
return;
screen_position.origin.X += shift;
screen_position.corner.X += shift;
if(show)
buffer_screen();
return;
case RIGHT:
if(screen_position.origin.X - shift < 0)
return;
screen_position.origin.X -= shift;
screen_position.corner.X -= shift;
buffer_screen();
return;
}
}
/////////////////////////////
int pcx_file_buffer(GrafBuffer* buf, loc pos, char* name, int col)
{
FILE* f;
if((f = fopen(name, "rb")) == NULL)
return 0; // Open PCX file
pcxheader p; // Read PCX header
if(!get_pcx_header(f, &p)) // Simple error handler
{
fclose(f);
return 0;
}
if(p.bitpx == 1 && p.nplanes == 1) // Trouble: after call to
{ // the pcx_bw_to_col() 8 bit
fclose(f); // rounded image will (possib-
pcx_bw_to_col(name, "tmp____u.pcz"); // ly) replace 16 bit one. To
delete name; // read new pcx header we need
name = strdup("tmp____u.pcz"); // additional call to header
if((f = fopen(name, "rb")) == NULL) // reader function
return 0;
get_pcx_header(f, &p);
}
int bplin; // bytes per line in same buffer if compatible, or in new buffer
int xsize = p.x2 - p.x1 + 1;
int ysize = p.y2 - p.y1 + 1;
if(pos.X + xsize >= buf->buf_dim.X // If picture is larger
|| pos.Y + ysize >= buf->buf_dim.Y) // than buffer - resize
{ // all data will be lost
buf->b_close();
buf->bound_size.X = buf->buf_dim.X = pos.X + xsize + 1;
buf->bound_size.Y =
(BOUND_SIZE / (::imagesize(0, 0, buf->bound_size.X - 1, 0)
- sizeof(imageP) - 2));
if(buf->bound_size.Y > buf->buf_dim.Y)
buf->bound_size.Y = buf->buf_dim.Y;
buf->buf_dim.Y = pos.Y + p.y2 - p.y1 + 1;
buf->b_open();
}
pcxheader work;
GrafBuffer* work_gb;
int start_bound;
int end_bound;
int x;
int y;
int start_x;
int plane_num = p.nplanes - 1; // number of current plane, cycle variable
if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx // if formates are
|| col != 16)
{ // incompatible
work_gb = // Create new buffer
new GrafBuffer(loc((p.x2 - p.x1 + 1 + 7) / 8 * 8,
p.y2 - p.y1 + 1),
"__work.buf", rect(0, 0, 10, 20), p.bitpx, p.nplanes);
if(!(work_gb->b_open())) // Not enough memory to open 2-th
{ // buffer
delete work_gb;
fclose(f);
return 0;
}
bplin = p.bplin; /* Bytes per line */
work_gb->clear();
start_bound = 0;
end_bound = (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
x = plane_num * bplin; // start x byte in source rectangle
y = start_x = 0;
}
else // formates are compatible
{ // Now we can call it for compatible and incompatible
work_gb = buf; // formates
put_pcx_header(NULL, &work, // tric to obtain bplin
loc(buf->bound_size.X, buf->bound_size.Y)); // for "bound" image
bplin = work.bplin;
start_bound = pos.Y / work_gb->bound_size.Y; // In "old" buffer
end_bound = (pos.Y + p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
x = pos.X * work_gb->bitpx / 8 + plane_num * bplin; // start x byte in source rectangle
y = pos.Y - work_gb->bound_size.Y * start_bound; // start y in current bound
start_x = (pos.X * work_gb->bitpx + 7) / 8; // start x byte in image
}
int w_data = work_gb->nplanes * bplin; // length of image line, bytes
int i = start_bound;
work_gb->get_bound(i);
int ex = 0;
buf->loaded = 1;
while(!ex)
{
int count = 1; // PCX counter
unsigned char ch = fgetc(f); // read char
if((ch & 0xC0 ) == 0xC0) // if two upper bits == 1
{
count = 63 & ch; // use 6 low bits as counter
ch = fgetc(f); // read the pattern
}
for(int j = 0; j < count; j++)
{
unsigned char ch1;
ch1 = work_gb->image->data[x + w_data * y];
work_gb->image->data[x + w_data * y] = ch;
x++;
if(x == bplin * plane_num + start_x + p.bplin)
{
work_gb->image->data[x + w_data * y - 1] =
(ch & (255 << xsize % 8))
| ((255 >> (8 - xsize % 8) & ch1));
// If end of scan line or end of plane
if(plane_num == 0) // If end of scan line
{
plane_num = work_gb->nplanes - 1;
x = start_x + plane_num * bplin;
if(y + 1 < work_gb->bound_size.Y
/* ! */ && i * work_gb->bound_size.Y + y + 1 < pos.Y + ysize)
y++;
else
{
work_gb->put_bound(i);
i++;
if(i < end_bound)
{
work_gb->get_bound(i);
y = 0;
}
else // Exit loop
{
fclose(f);
ex = 1;
break;
}
}
}
else // End of plane
{
plane_num--;
x = plane_num * bplin + start_x;
}
}
}
}
if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx // if formates are
|| col != 16)
{ // incompatible
int src_max_color = s_max_color(p.bitpx, p.nplanes); // max color in src
int dest_max_color = getmaxcolor();
int color_mult = get_color_mult(src_max_color, dest_max_color); // Simple color filter
int color_mult_15 = get_color_mult(src_max_color, 15);
int work_y = 0; // in "new" buffer
int bound1 = pos.Y / buf->bound_size.Y;
int bound2 = 0;
int y = pos.Y - bound1 * buf->bound_size.Y; // Inside (buf) image
work_gb->get_bound(0); // Read src and det bounds
buf->get_bound(bound1);
while(1)
{
if(work_y == work_gb->bound_size.Y) // End of (work) bound
{
work_y = 0; // Prepare to load new (work)
bound2++; // bound
if(bound2 == (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1)
{ // Last bound to read
buf->put_bound(bound1); // flash the rest and exit
break;
}
work_gb->get_bound(bound2); // Else - load next bound
}
if(y == buf->bound_size.Y) // End of (buf) bound
{
buf->put_bound(bound1); // Swap modified bound
y = 0; // and prepare to load next
bound1++;
buf->get_bound(bound1); // Load next (buf) bound
}
int end_y = (bound1 == (pos.Y + p.y2 - p.y1 + 1)
/ buf->bound_size.Y)
? pos.Y + p.y2 - p.y1 + 1 - bound1 * buf->bound_size.Y
: buf->bound_size.Y;
for(; y < end_y && work_y < work_gb->bound_size.Y;
y++, work_y++)
{
for(int x = pos.X; x < pos.X + p.x2 - p.x1 + 1; x++)
{
int pix = image_get_pixel(work_gb->image,
loc(x - pos.X, work_y), p.bitpx, p.nplanes);
if(dest_max_color < src_max_color)
{
if(src_max_color <= 15)
pix = (bw_pix(pix * color_mult_15, x,
y + bound1 * buf->bound_size.Y))
? pix / color_mult
: dest_max_color - pix / color_mult;
else
pix = (bw_pix(pix / color_mult_15, x,
y + bound1 * buf->bound_size.Y))
? pix / color_mult
: dest_max_color - pix / color_mult;
}
else
if(dest_max_color > src_max_color)
pix = pix * color_mult;
if(pix != col)
image_put_pixel(buf->image, loc(x, y), pix,
buf->bitpx, buf->nplanes);
}
}
if(bound1 == (pos.Y + p.y2 - p.y1 + 1) / buf->bound_size.Y)
{
buf->put_bound(bound1);
break;
}
}
work_gb->b_close();
delete work_gb;
}
return 1;
}
///////////////////////////
inline void pcx_put_char(uchar count, uchar ch, FILE* f)
{
if(count > 1 || (0xC0 == (0xC0 & ch)))
fputc(count | 128 | 64, f); // Write counter
fputc(ch, f); // Write pattern
}
//////////////////////////
void GrafBuffer::pcx_buffer_file(rect src, char* name)
{
if(src.right() >= bound_size.X) // If any mistake
return;
FILE* f = fopen(name, "w+b"); // Open target file
pcxheader p; // Put header
put_pcx_header(f, &p, loc(src.width(), src.height())); // of target file
pcxheader work; // The pseudo-header
work.bitpx = 1; // contains information
work.nplanes = 4; // about current
work.x1 = 0; // graphics buffer
work.y1 = 0;
work.x2 = bound_size.X - 1;
work.y2 = bound_size.Y - 1;
work.bplin = (bound_size.X + 7) >> 3;
int start_bound = src.origin.Y / bound_size.Y; // Start buffer bound
int end_bound = src.corner.Y / bound_size.Y + 1;
int plane_num = 3; // Number of current plane,
// work.nplanes - 1 == 3 for VGA/EGA
int w_data = work.nplanes * work.bplin; // Length of image line, bytes
uchar count = 1; // PCX counter
int start_x = src.origin.X / 8; // Between beginning of plane and
// beginning of rect, bytes
int src_bytes = src.width() / 8; // Significant bytes in src scan line
int x = start_x + plane_num * work.bplin; // Start x in current plane of
// source rectangle
int i = start_bound; // Counter of biunds
int y = src.origin.Y - bound_size.Y * i; // Start y in current bound
get_bound(i); // Read bound
unsigned char ch = image->data[x + w_data * y]; // Get start char
int plane_end = x + src_bytes; // End of current plane
while(1) // The main cycle
{
x++; // Move the pointer in image
if(x == plane_end)
{ // End of scan line or end of plane.
if(plane_num != 0) // If it is end of plane,
{ // not of scan line.
plane_num--; // 3-2-1-0 in BGI == 0-1-2-3 in PCX
x = plane_num * work.bplin + start_x; // Start x in
plane_end -= work.bplin; // new plane.
}
else // It is end of scan line
{
if(i < end_bound) // Not last bound.
{
plane_num = 3; // work.nplanes - 1;
x = start_x + 3 * work.bplin; // Start x in 4th plane
plane_end = x + src_bytes; // End of 4th plane
if(y + 1 == bound_size.Y) // If bottom of bound
{
i++; // Go to next bound
y = 0;
get_bound(i); // Read new bound
}
else
y++; // Continue with this bound
/* The following code, marked !! is absolutely unnecessary and ineffective.
But Painbrush use stop-on-the-scan-line technology. I don't know why.
This code is compatible with Paintbrush.
*/
pcx_put_char(count, ch, f); // !!
count = 0; // !!
ch = image->data[x + w_data * y]; // !!
}
else // Last bound
{
pcx_put_char(count, ch, f); // Write counter last time
break; // exit the loop
}
}
}
if(ch == image->data[x + w_data * y]) // If current data is the same
{ // as previous, keeped in ch
if(count == 63)
{
pcx_put_char(count, ch, f);
count = 1;
}
else
count++;
}
else // New data value
{
pcx_put_char(count, ch, f); // Flash old counter
count = 1; // Start new counter
ch = image->data[x + w_data * y]; // Read next
}
}
fclose(f);
}
/////////////////////////
/*
void main()
{
int gdriver = DETECT, gmode;
initgraph(&gdriver, &gmode, "");
GrafBuffer* g = new GrafBuffer(loc(1001, 1000), "work.buf",
rect(0, 0, 600, 400));
g->b_open();
g->clear();
char* name = strdup("c:\\myprog\\sova.pcx");
pcx_file_buffer(g, loc(0, 0), name);//, LIGHTGRAY);
g->buffer_screen();
g->pcx_buffer_file(rect(64, 40, 191, 300), "work.pcx");
pcx_file_buffer(g, loc(0, 0), "work.pcx");
g->buffer_screen();
g->b_close();
delete g;
delete name;
closegraph();
}
*/